using System;
using System.Collections.Generic;
using System.Linq;
using Engine;
using Engine.Graphics;
using Engine.Input;
using Game;

namespace RuthlessConquest {
    public class HumanPlayer : Player {
        public bool GameResultDialogShown;
        public DynamicArray<VisualRoute> VisualRoutes = new();
        public DynamicArray<VisualRoute> TmpVisualRoutes = new();
        public Vector2? DragStartPosition;
        public Vector2? DragEndPosition;
        public const string fName = "RCHumanPlayer";

        public bool BlinkPlanets { get; set; }

        public HumanPlayer() { }

        public HumanPlayer(PlayerDescription playerDescription) : base(playerDescription) { }

        public void AddOrderToOutgoingList(Planet sourcePlanet,
            IEnumerable<Planet> route,
            int shipsCount,
            bool launchSatellite,
            Faction giftToFaction) {
            int num = MathUtils.Min(shipsCount, sourcePlanet.ShipsCount);
            if ((num > 0 && route.Any()) || launchSatellite) {
                StepModule.OutgoingOrders.Add(
                    new Order {
                        ShipsCount = num,
                        PlanetIndex = PlanetsModule.Planets.IndexOf(sourcePlanet),
                        RouteIndexes = route.Select(p => PlanetsModule.Planets.IndexOf(p)).ToDynamicArray(),
                        LaunchSatellite = launchSatellite,
                        GiftToFaction = giftToFaction
                    }
                );
            }
        }

        public void IssueMoveOrder(Planet targetPlanet, IEnumerable<Planet> sourcePlanets, float strength, Faction giftToFaction) {
            bool flag = false;
            bool flag2 = false;
            bool flag3 = true;
            foreach (Planet sourcePlanet in sourcePlanets) {
                if (sourcePlanet != targetPlanet) {
                    if (sourcePlanet.ContinuousOrderRoute != null) {
                        flag = true;
                        sourcePlanet.ContinuousOrderRoute = null;
                    }
                    IEnumerable<Planet> planets = (IEnumerable<Planet>)(giftToFaction != Faction.None
                        ? PlanetsModule.Planets.Where(p => p.Faction == sourcePlanet.Faction || p.Faction == giftToFaction)
                        : (object)PlanetsModule.Planets);
                    DynamicArray<Planet> dynamicArray = RouteFinderModule.FindRoute(sourcePlanet, targetPlanet, planets);
                    if (dynamicArray.Count > 0) {
                        flag3 = false;
                        flag2 = true;
                        AddOrderToOutgoingList(
                            sourcePlanet,
                            dynamicArray,
                            (int)MathUtils.Ceiling(sourcePlanet.ShipsCount * strength),
                            false,
                            giftToFaction
                        );
                        dynamicArray.Insert(0, sourcePlanet);
                        AddVisualRoute(new VisualRoute(dynamicArray, Ship.GetColor(giftToFaction == Faction.None ? Faction : giftToFaction)));
                        AudioManager.PlaySound(Sounds.Order, true);
                    }
                }
            }
            if (flag) {
                Game.Screen.MessagesListWidget.AddMessage(LanguageControl.Get(fName, "1"), GetColor(Faction), true);
            }
            if (flag3) {
                Game.Screen.MessagesListWidget.AddMessage(LanguageControl.Get(fName, "2"), GetColor(Faction), true);
            }
            if (flag2) {
                DeselectAllPlanets();
            }
        }

        public void IssueContinuousMoveOrder(Planet targetPlanet, IEnumerable<Planet> sourcePlanets) {
            bool flag = false;
            foreach (Planet sourcePlanet in sourcePlanets) {
                if (sourcePlanet != targetPlanet) {
                    DynamicArray<Planet> dynamicArray = RouteFinderModule.FindRoute(sourcePlanet, targetPlanet, true);
                    if (dynamicArray.Count > 0) {
                        AddOrderToOutgoingList(sourcePlanet, dynamicArray, sourcePlanet.ShipsCount, false, Faction.None);
                        flag = true;
                        sourcePlanet.ContinuousOrderRoute = dynamicArray.ToDynamicArray();
                        dynamicArray.Insert(0, sourcePlanet);
                        AddVisualRoute(new VisualRoute(dynamicArray, Ship.GetColor(Faction)));
                        AudioManager.PlaySound(Sounds.Order, true);
                    }
                }
            }
            if (flag) {
                Game.Screen.MessagesListWidget.AddMessage(LanguageControl.Get(fName, "3"), Planet.GetColor(Faction), true);
                DeselectAllPlanets();
            }
        }

        public void IssueLaunchSatelliteOrder(Planet planet) {
            if (planet.CanLaunchSatellite(false)) {
                AddOrderToOutgoingList(planet, new Planet[0], 0, true, Faction.None);
                DeselectAllPlanets();
            }
        }

        public override void OnAdded() {
            base.OnAdded();
            BlinkPlanets = IsControllingPlayer;
        }

        public override void Update() {
            if (PlayersModule.ControllingPlayer != this) {
                return;
            }
            if (StepModule.IsGameStarted
                && StepModule.CountdownStepsLeft <= 0
                && !PlayersModule.IsGameFinished) {
                WidgetInput input = Game.Screen.GameWidget.Input;
                if (input.Drag.HasValue) {
                    if (!DragStartPosition.HasValue) {
                        Widget widget = Game.Screen.GameWidget.HitTestGlobal(input.Drag.Value);
                        if (widget == Game.Screen.GameWidget
                            || (widget is PlayerLabelWidget && widget.IsChildWidgetOf(Game.Screen))) {
                            DragStartPosition = input.Drag;
                        }
                    }
                    if (DragStartPosition.HasValue) {
                        DragEndPosition = input.Drag.Value;
                        HandleDrag(new Segment2(DragStartPosition.Value, DragEndPosition.Value));
                    }
                }
                else {
                    if (DragEndPosition != null) {
                        DragEndPosition = null;
                        goto EndInput;
                    }
                    DragStartPosition = null;
                    if (input.Hold.HasValue
                        && Game.Screen.GameWidget.HitTestGlobal(input.Hold.Value) == Game.Screen.GameWidget) {
                        HandleHold(input.Hold.Value);
                    }
                    else if (input.Click.HasValue
                        && Game.Screen.GameWidget.HitTestGlobal(input.Click.Value.Start) == Game.Screen.GameWidget) {
                        HandleClick(input.Click.Value);
                    }
                    else if (input.SpecialClick.HasValue
                        && Game.Screen.GameWidget.HitTestGlobal(input.SpecialClick.Value.Start) == Game.Screen.GameWidget) {
                        HandleSecondaryClick(input.SpecialClick.Value);
                    }
                }
            }
            else {
                DragStartPosition = null;
                DragEndPosition = null;
            }
            EndInput:
            PlayerLabelWidget playerLabelWidget = Game.Screen.FindPlayerLabel(this);
            if (playerLabelWidget != null
                && playerLabelWidget.IsSatelliteButtonClicked) {
                Game.StepModule.OutgoingOrders.Add(new Order { EnableDisableSatellites = !AreSatellitesEnabled });
                if (AreSatellitesEnabled) {
                    Game.Screen.MessagesListWidget.AddMessage(LanguageControl.Get(fName, "4"), GetColor(Faction), false);
                    AudioManager.PlaySound(Sounds.Shutdown, true, 0.5f);
                }
                else {
                    Game.Screen.MessagesListWidget.AddMessage(LanguageControl.Get(fName, "5"), GetColor(Faction), false);
                    AudioManager.PlaySound(Sounds.Startup, true, 0.5f);
                }
            }
            if (!GameResultDialogShown
                && Status != 0
                && Time.FrameStartTime > StatusChangeTime + 2.0) {
                GameResultDialogShown = true;
                DialogsManager.ShowDialog(null, new GameResultDialog(this));
            }
        }

        public override void Draw(Color colorTransform) {
            if (PlayersModule.ControllingPlayer != this) {
                return;
            }
            TmpVisualRoutes.Clear();
            TmpVisualRoutes.AddRange(VisualRoutes);
            foreach (VisualRoute tmpVisualRoute in TmpVisualRoutes) {
                tmpVisualRoute.Draw(colorTransform);
                if (tmpVisualRoute.TimeToLive <= 0f) {
                    RemoveVisualRoute(tmpVisualRoute);
                }
            }
            if (DragStartPosition.HasValue
                && DragEndPosition.HasValue) {
                Vector2 corner = Vector2.Transform(DragStartPosition.Value, CameraModule.ScreenToWorldMatrix);
                Vector2 corner2 = Vector2.Transform(DragEndPosition.Value, CameraModule.ScreenToWorldMatrix);
                FlatBatch2D flatBatch2D = CameraModule.PrimitivesRenderer.FlatBatch(10);
                flatBatch2D.QueueQuad(corner, corner2, 0f, Color.White * 0.2f);
                flatBatch2D.QueueRectangle(corner, corner2, 0f, Color.White * 0.5f);
            }
        }

        public void HandleClick(Segment2 click) {
            IEnumerable<Planet> enumerable = PlanetsModule.Planets.Where(p => p.IsSelected);
            Planet planet = PlanetsModule.PickPlanet(click.Start);
            Planet planet2 = PlanetsModule.PickPlanet(click.End);
            Planet planet3 = planet == planet2 ? planet : null;
            if (planet3 != null) {
                if (Keyboard.IsKeyDown(Key.Shift)
                    && planet3.Faction == Faction) {
                    BlinkPlanets = false;
                    planet3.IsSelected = !planet3.IsSelected;
                    AudioManager.PlaySound(planet3.IsSelected ? Sounds.Select : Sounds.Deselect, false);
                }
                else if (!Keyboard.IsKeyDown(Key.Shift)
                    && enumerable.Count() > 0) {
                    if (enumerable.Count() > 1
                        || enumerable.ElementAt(0) != planet3) {
                        IssueMoveOrder(planet3, enumerable, SettingsManager.DefaultFleetStrength, Faction.None);
                    }
                    else if (enumerable.Count() == 1
                        && enumerable.ElementAt(0) == planet3) {
                        DeselectAllPlanets();
                        AudioManager.PlaySound(Sounds.Deselect, false);
                        if (planet3.ContinuousOrderRoute != null) {
                            planet3.ContinuousOrderRoute = null;
                            Game.Screen.MessagesListWidget.AddMessage(LanguageControl.Get(fName, "1"), GetColor(Faction), true);
                        }
                    }
                }
                else if (planet3.Faction == Faction) {
                    DeselectAllPlanets();
                    BlinkPlanets = false;
                    planet3.IsSelected = true;
                    AudioManager.PlaySound(Sounds.Select, false);
                }
            }
            else if (!Keyboard.IsKeyDown(Key.Shift)) {
                if (enumerable.Count() > 0) {
                    AudioManager.PlaySound(Sounds.Deselect, false);
                }
                DeselectAllPlanets();
            }
        }

        public void HandleSecondaryClick(Segment2 click) {
            Planet planet = PlanetsModule.PickPlanet(click.Start);
            Planet planet2 = PlanetsModule.PickPlanet(click.End);
            Planet planet3 = planet == planet2 ? planet : null;
            if (planet3 != null) {
                OrderDialog orderDialog = new(this, planet3, PlanetsModule.Planets.Where(p => p.IsSelected));
                if (orderDialog.ListWidget.Items.Count > 0) {
                    AudioManager.PlaySound(Sounds.Click, false);
                    DialogsManager.ShowDialog(Game.Screen, orderDialog);
                    BlinkPlanets = false;
                }
            }
        }

        public void HandleHold(Vector2 hold) {
            Planet planet = PlanetsModule.PickPlanet(hold);
            if (planet != null) {
                OrderDialog orderDialog = new(this, planet, PlanetsModule.Planets.Where(p => p.IsSelected));
                if (orderDialog.ListWidget.Items.Count > 0) {
                    AudioManager.PlaySound(Sounds.Click, false);
                    DialogsManager.ShowDialog(Game.Screen, orderDialog);
                    BlinkPlanets = false;
                }
            }
        }

        public void HandleDrag(Segment2 drag) {
            int num = PlanetsModule.Planets.Where(p => p.IsSelected).Count();
            DeselectAllPlanets();
            Vector2 v = Vector2.Transform(drag.Start, CameraModule.ScreenToWorldMatrix);
            Vector2 v2 = Vector2.Transform(drag.End, CameraModule.ScreenToWorldMatrix);
            BoundingRectangle boundingRectangle = new(Vector2.Min(v, v2), Vector2.Max(v, v2));
            foreach (Planet planet in PlanetsModule.Planets) {
                if (planet.Faction == Faction
                    && boundingRectangle.Intersection(new BoundingCircle(new Vector2(planet.Position), planet.Radius))) {
                    BlinkPlanets = false;
                    planet.IsSelected = true;
                }
            }
            if (PlanetsModule.Planets.Where(p => p.IsSelected).Count() > num) {
                AudioManager.PlaySound(Sounds.Select, true);
            }
        }

        public void DeselectAllPlanets() {
            foreach (Planet planet in PlanetsModule.Planets) {
                planet.IsSelected = false;
            }
        }

        public void AddVisualRoute(VisualRoute visualRoute) {
            if (visualRoute.Game != null) {
                throw new InvalidOperationException();
            }
            VisualRoutes.Add(visualRoute);
            visualRoute.Game = Game;
        }

        public void RemoveVisualRoute(VisualRoute visualRoute) {
            if (visualRoute.Game != Game) {
                throw new InvalidOperationException();
            }
            VisualRoutes.Remove(visualRoute);
            visualRoute.Game = null;
        }
    }
}